#ifndef DEBUG_PMU_DWT_H
#define DEBUG_PMU_DWT_H
#include "cmsis_compiler.h"
#include <stdint.h>
#include <stddef.h>

extern uint32_t SystemCoreClock;
/* CPU Clock Frequency */
#define CPU_CLOCK_FREQ    SystemCoreClock

/**
  \brief  Structure type to access the Data Watchpoint and Trace Register (DWT).
 */
typedef struct
{
  volatile uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  Control Register */
  volatile uint32_t CYCCNT;                 /*!< Offset: 0x004 (R/W)  Cycle Count Register */
} ARM_DWT_Type;

/**
  \brief  Structure type to access the Core Debug Register (CoreDebug).
 */
typedef struct
{
  volatile uint32_t DHCSR;                  /*!< Offset: 0x000 (R/W)  Debug Halting Control and Status Register */
  volatile uint32_t DCRSR;                  /*!< Offset: 0x004 ( /W)  Debug Core Register Selector Register */
  volatile uint32_t DCRDR;                  /*!< Offset: 0x008 (R/W)  Debug Core Register Data Register */
  volatile uint32_t DEMCR;                  /*!< Offset: 0x00C (R/W)  Debug Exception and Monitor Control Register */
} ARM_CoreDebug_Type;

/* Memory mapping of Core Hardware */
#define ARM_DWT_BASE            (0xE0001000UL)                            /*!< DWT Base Address */
#define ARM_CoreDebug_BASE      (0xE000EDF0UL)                            /*!< Core Debug Base Address */

#define PMU_DWT                 ((ARM_DWT_Type       *)     ARM_DWT_BASE      )   /*!< DWT configuration struct */
#define PMU_CoreDebug           ((ARM_CoreDebug_Type *)     ARM_CoreDebug_BASE)   /*!< Core Debug configuration struct */

#define CoreDebug_DEMCR_TRCENA  (0x01000000UL)
#define DWT_CTRL_CYCCNTENA      (0x00000001UL)

/********************* FUNCTION API *************************/
void PMU_DWT_Initialize(void);
void PMU_DWT_DeInitialize(void);
void PMU_DWT_DelayUs(uint32_t delay_us);
void PMU_DWT_DelayMs(uint32_t delay_ms);
// void PMU_DWT_CounterReset(void);
// void PMU_DWT_CounterEnable(void);
// void PMU_DWT_CounterDisable(void);
// uint32_t PMU_DWT_CounterGet(void);


/**
 * @brief DWT Counter Reset to 0.
 * 
 * @return none
 */
__STATIC_FORCEINLINE void PMU_DWT_CounterReset(void)
{
  PMU_DWT->CYCCNT = 0U; 
}

/**
 * @brief DWT Counter Enable.
 * 
 * @return none
 */
__STATIC_FORCEINLINE void PMU_DWT_CounterEnable(void)
{
    PMU_DWT->CTRL |= DWT_CTRL_CYCCNTENA;
}

/**
 * @brief DWT Counter Disable.
 * 
 * @return none
 */
__STATIC_FORCEINLINE void PMU_DWT_CounterDisable(void)
{
    PMU_DWT->CTRL &= ~DWT_CTRL_CYCCNTENA;
}

/**
 * @brief Get DWT Counters.
 * 
 * @return none
 */
__STATIC_FORCEINLINE uint32_t PMU_DWT_CounterGet(void)
{
    return PMU_DWT->CYCCNT;
}

/**
 * @brief DWT Counter Calibrate
 * 
 * @return none
 */
__STATIC_FORCEINLINE uint32_t PMU_DWT_CounterCalibrate(void)
{
	static uint32_t t1,t2,delta;
	t1 = PMU_DWT_CounterGet();
	t2 = PMU_DWT_CounterGet();
	delta = t2 - t1;
	return delta;
}

#endif //PMU_DWT_H
